#include "cmd_process.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_ble_api.h"
#include "esp_gatt_common_api.h"
#include "esp_gatts_api.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "user_bt.h"
#include "user_utils.h"
#include <string.h>

#define TAG "BLE_MIN"

#define SERVICE_UUID 0x1234       // service uuid
#define CHAR_UUID_CMD 0x1235      // json cmd uuid
#define CHAR_UUID_TFN_UUID 0x1240 // trans file notify uuid
#define CHAR_UUID_TFI_UUID 0x1241 // trans file indicate uuid
#define CHAR_UUID_RF_UUID 0x1250  // recv file uuid

#define PROFILE_NUM 4

#define MAX_CONN_NUM 1
#define IOS_MTU_MAX 500 // iOS 最大MTU

static void ble_transmit_task(void *arg);
static void cmd_write_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
static void recev_file_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);

volatile bool ble_transmit_flag = false; // 控制标志位

typedef struct {
    bool in_use;              // 是否已连接
    uint16_t conn_id;         // BLE 连接 ID
    esp_bd_addr_t remote_bda; // 远端设备地址（MAC）
} ble_conn_info_t;
ble_conn_info_t ble_conn_table[MAX_CONN_NUM];

typedef struct {
    uint16_t char_handle;      // 特征值
    uint16_t descr_handle;     // 特征值描述符 例CCDD
    esp_bt_uuid_t uuid;        // 特征或描述符的 UUID
    esp_gatt_perm_t perm;      // 权限设置，如 ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE
    esp_gatt_char_prop_t prop; // 特征属性，如 ESP_GATT_CHAR_PROP_BIT_READ | WRITE | NOTIFY
    esp_attr_value_t val;      // 特征的初始值及其长度设置
    void (*event_handler)(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); // 写入处理函数
} uuid_node_t;

typedef struct {
    esp_gatt_if_t gatts_if;
    esp_gatt_srvc_id_t service_id;
    uint16_t service_handle;
    uuid_node_t uuid_nodes[PROFILE_NUM];
} gatt_service_info_t;
#define DEFAULT_ATTR_VALUE {.attr_max_len = 20, .attr_len = sizeof(uint8_t), .attr_value = (uint8_t *)"\0"}

static gatt_service_info_t gatt_service_info = {
    .service_id = {.is_primary = true, .id.inst_id = 0, .id.uuid.len = ESP_UUID_LEN_16, .id.uuid.uuid.uuid16 = SERVICE_UUID}, // 服务 ID
    .uuid_nodes[CMD_INDEX].uuid = {.len = ESP_UUID_LEN_16, .uuid.uuid16 = CHAR_UUID_CMD}, // ===== JSON CMD（ESP32 ← → 手机）=====
    .uuid_nodes[TFN_INDEX].uuid = {.len = ESP_UUID_LEN_16,
                                   .uuid.uuid16 = CHAR_UUID_TFN_UUID}, // ===== 文件下发通道（ESP32 → 手机）===== notify
    .uuid_nodes[TFI_INDEX].uuid = {.len = ESP_UUID_LEN_16,
                                   .uuid.uuid16 = CHAR_UUID_TFI_UUID}, // ===== 文件下发通道（ESP32 → 手机）===== indicate
    .uuid_nodes[RF_INDEX].uuid = {.len = ESP_UUID_LEN_16, .uuid.uuid16 = CHAR_UUID_RF_UUID}, // ===== 文件上传通道（ESP32 ← 手机）=====

    .uuid_nodes[CMD_INDEX].perm = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
    .uuid_nodes[TFN_INDEX].perm = ESP_GATT_PERM_READ,
    .uuid_nodes[TFI_INDEX].perm = ESP_GATT_PERM_READ,
    .uuid_nodes[RF_INDEX].perm = ESP_GATT_PERM_WRITE,

    .uuid_nodes[CMD_INDEX].prop = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_INDICATE,
    .uuid_nodes[TFN_INDEX].prop = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_NOTIFY,
    .uuid_nodes[TFI_INDEX].prop = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_INDICATE,
    .uuid_nodes[RF_INDEX].prop = ESP_GATT_CHAR_PROP_BIT_WRITE,

    .uuid_nodes[CMD_INDEX].val = DEFAULT_ATTR_VALUE,
    .uuid_nodes[TFN_INDEX].val = DEFAULT_ATTR_VALUE,
    .uuid_nodes[TFI_INDEX].val = DEFAULT_ATTR_VALUE,
    .uuid_nodes[RF_INDEX].val = DEFAULT_ATTR_VALUE,

    .uuid_nodes[CMD_INDEX].event_handler = cmd_write_handler,
    .uuid_nodes[RF_INDEX].event_handler = recev_file_handler,
};

// 广播数据
static uint8_t adv_config_done = 0;
static esp_ble_adv_data_t adv_data = {
    .set_scan_rsp = false,
    .include_name = true,
    .include_txpower = false,
    .min_interval = 0x20,
    .max_interval = 0x40,
    .appearance = 0x00,
    .manufacturer_len = 0,
    .p_manufacturer_data = NULL,
    .service_data_len = 0,
    .p_service_data = NULL,
    .service_uuid_len = 0,
    .p_service_uuid = NULL,
    .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};

// scan response data
static esp_ble_adv_data_t scan_rsp_data = {
    .set_scan_rsp = true,
    .include_name = true,
    .include_txpower = true,
    .appearance = 0x00,
    .manufacturer_len = 0,       // TEST_MANUFACTURER_DATA_LEN,
    .p_manufacturer_data = NULL, //&test_manufacturer[0],
    .service_data_len = 0,
    .p_service_data = NULL,
    .service_uuid_len = 0,
    .p_service_uuid = NULL,
    .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};

// 广播参数
static esp_ble_adv_params_t adv_params = {
    .adv_int_min = 0x20,
    .adv_int_max = 0x40,
    .adv_type = ADV_TYPE_IND,
    .own_addr_type = BLE_ADDR_TYPE_PUBLIC,
    .channel_map = ADV_CHNL_ALL,
    .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};

// 广播处理
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
    switch (event) {
    case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
        if (param->adv_start_cmpl.status == ESP_BT_STATUS_SUCCESS) {
            ESP_LOGI(TAG, "Advertising started");
        } else {
            ESP_LOGE(TAG, "Failed to start advertising");
        }
        break;
    default:
        break;
    }
}

// GATT 事件处理
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
    static int char_add_index = 0; // 状态机式添加char和descr
    switch (event) {
    case ESP_GATTS_REG_EVT: // 注册事件
        ESP_LOGI(TAG, "GATT server registered");
        // config adv data
        esp_err_t ret = esp_ble_gap_config_adv_data(&adv_data);
        if (ret) {
            ESP_LOGE(TAG, "config adv data failed, error code = %x", ret);
        }
        // config scan response data
        ret = esp_ble_gap_config_adv_data(&scan_rsp_data);
        if (ret) {
            ESP_LOGE(TAG, "config scan response data failed, error code = %x", ret);
        }
        esp_ble_gatts_create_service(gatts_if, &gatt_service_info.service_id, 12);
        gatt_service_info.gatts_if = gatts_if;
        break;
    case ESP_GATTS_READ_EVT: {
        ESP_LOGI(TAG, "Characteristic read, conn_id %d, trans_id %" PRIu32 ", handle %d", param->read.conn_id, param->read.trans_id,
                 param->read.handle);
        esp_gatt_rsp_t rsp;
        memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
        rsp.attr_value.handle = param->read.handle;
        rsp.attr_value.len = 4;
        rsp.attr_value.value[0] = 0xde;
        rsp.attr_value.value[1] = 0xed;
        rsp.attr_value.value[2] = 0xbe;
        rsp.attr_value.value[3] = 0xef;
        esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp);
        break;
    }
    case ESP_GATTS_WRITE_EVT:
        // ESP_LOGI(TAG, "Characteristic write, conn_id %d, trans_id %" PRIu32 ", handle %d", param->write.conn_id, param->write.trans_id,
        //          param->write.handle);
        // ESP_LOGI(TAG, "cmd describe handle 0x%04x", gatt_service_info.uuid_nodes[CMD_INDEX].descr_handle);
        for (int i = 0; i < PROFILE_NUM; i++) {
            if (param->write.handle == gatt_service_info.uuid_nodes[i].descr_handle && param->write.len == 2) {
                uint16_t descr_value = param->write.value[1] << 8 | param->write.value[0];
                if (descr_value == 0x0001) {
                    ESP_LOGI(TAG, "Notification enable");
                } else if (descr_value == 0x0002) {
                    ESP_LOGI(TAG, "Indication enable");
                } else if (descr_value == 0x0000) {
                    ESP_LOGI(TAG, "Notification/Indication disable");
                } else {
                    ESP_LOGE(TAG, "Unknown descriptor value");
                    ESP_LOG_BUFFER_HEX(TAG, param->write.value, param->write.len);
                    return;
                }
                if (param->write.need_rsp) {
                    esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
                    return;
                }
            }
            if (param->write.handle == gatt_service_info.uuid_nodes[i].char_handle) {
                // ESP_LOG_BUFFER_HEX(TAG, param->write.value, param->write.len);
                if (gatt_service_info.uuid_nodes[i].event_handler && param->write.len > 0) {
                    gatt_service_info.uuid_nodes[i].event_handler(event, gatts_if, param);
                }
                if (param->write.need_rsp) {
                    esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
                }
                break;
            }
        }
        break;
    case ESP_GATTS_CREATE_EVT:
        ESP_LOGI(TAG, "Service create, status %d, service_handle %d", param->create.status, param->create.service_handle);
        gatt_service_info.service_handle = param->create.service_handle;
        esp_ble_gatts_add_char(gatt_service_info.service_handle, &gatt_service_info.uuid_nodes[0].uuid,
                               gatt_service_info.uuid_nodes[0].perm, gatt_service_info.uuid_nodes[0].prop,
                               &gatt_service_info.uuid_nodes[0].val, NULL);
        char_add_index = 0;
        break;
    case ESP_GATTS_ADD_CHAR_EVT:
        ESP_LOGI(TAG, "Characteristic add, status %d, attr_handle %d, service_handle %d", param->add_char.status,
                 param->add_char.attr_handle, param->add_char.service_handle);
        gatt_service_info.uuid_nodes[char_add_index].char_handle = param->add_char.attr_handle;
        esp_bt_uuid_t descr_uuid = {.len = ESP_UUID_LEN_16, .uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG};
        esp_err_t add_descr_ret = esp_ble_gatts_add_char_descr(gatt_service_info.service_handle, &descr_uuid,
                                                               ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL);
        if (add_descr_ret) {
            ESP_LOGE(TAG, "add char descr failed, error code =%x", add_descr_ret);
        }
        break;
    case ESP_GATTS_ADD_CHAR_DESCR_EVT:
        ESP_LOGI(TAG, "Descriptor added: handle=0x%04x", param->add_char_descr.attr_handle);
        gatt_service_info.uuid_nodes[char_add_index].descr_handle = param->add_char_descr.attr_handle;
        char_add_index++;
        if (char_add_index < PROFILE_NUM) {
            esp_ble_gatts_add_char(gatt_service_info.service_handle, &gatt_service_info.uuid_nodes[char_add_index].uuid,
                                   gatt_service_info.uuid_nodes[char_add_index].perm, gatt_service_info.uuid_nodes[char_add_index].prop,
                                   &gatt_service_info.uuid_nodes[char_add_index].val, NULL);
        } else {
            ESP_LOGI(TAG, "All characteristics and descriptors added");
            esp_ble_gatts_start_service(gatt_service_info.service_handle);
        }
        break;

    case ESP_GATTS_MTU_EVT:
        ESP_LOGI(TAG, "ESP_GATTS_MTU_EVT, MTU size = %d", param->mtu.mtu);
        ble_transmit_flag = true;
        break;
    case ESP_GATTS_CONNECT_EVT:
        ESP_LOGI(TAG, "Device connected");
        uint16_t conn_id = param->connect.conn_id;
        esp_bd_addr_t remote_bda;
        memcpy(remote_bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));

        // 打印连接设备的MAC地址
        ESP_LOGI(TAG, "Connected device address: %02X:%02X:%02X:%02X:%02X:%02X, connID:%d", remote_bda[0], remote_bda[1], remote_bda[2],
                 remote_bda[3], remote_bda[4], remote_bda[5], conn_id);

        // 填入 ble_conn_table
        for (int i = 0; i < MAX_CONN_NUM; i++) {
            if (!ble_conn_table[i].in_use) {
                ble_conn_table[i].in_use = true;
                ble_conn_table[i].conn_id = conn_id;
                memcpy(ble_conn_table[i].remote_bda, remote_bda, sizeof(esp_bd_addr_t));
                ESP_LOGI(TAG, "Connection saved in slot %d", i);
                break;
            }
        }

        break;
    case ESP_GATTS_DISCONNECT_EVT:
        ESP_LOGI(TAG, "Device disconnected");

        ble_transmit_flag = false; // 测试用
        // 清除连接表中对应的连接信息
        for (int i = 0; i < MAX_CONN_NUM; i++) {
            if (ble_conn_table[i].in_use && ble_conn_table[i].conn_id == param->disconnect.conn_id) {
                ble_conn_table[i].in_use = false;
                memset(&ble_conn_table[i], 0, sizeof(ble_conn_info_t));
                ESP_LOGI(TAG, "Connection slot %d released", i);
                break;
            }
        }

        esp_ble_gap_start_advertising(&adv_params);
        break;
    default:
        break;
    }
}

// 初始化 BLE
void ble_init() {
    // 初始化蓝牙控制器
    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    esp_err_t ret = esp_bt_controller_init(&bt_cfg);
    if (ret) {
        ESP_LOGE(TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(ret));
        return;
    }
    ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
    if (ret) {
        ESP_LOGE(TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
        return;
    }

    // 初始化并启用 Bluedroid
    ret = esp_bluedroid_init();
    if (ret) {
        ESP_LOGE(TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
        return;
    }
    ret = esp_bluedroid_enable();
    if (ret) {
        ESP_LOGE(TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
        return;
    }

    // 设置设备名称
    esp_ble_gap_set_device_name(devInfo.deviceName);

    // 注册 GAP 和 GATT 事件处理
    ret = esp_ble_gatts_register_callback(gatts_event_handler);
    if (ret) {
        ESP_LOGE(TAG, "gatts register error, error code = %x", ret);
        return;
    }
    ret = esp_ble_gap_register_callback(gap_event_handler);
    if (ret) {
        ESP_LOGE(TAG, "gap register error, error code = %x", ret);
        return;
    }

    // 注册一个 GATT 应用（APP_ID = 0）
    ret = esp_ble_gatts_app_register(0);
    if (ret) {
        ESP_LOGE(TAG, "gatts app register error, error code = %x", ret);
        return;
    }

    // 设置mtu
    esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(IOS_MTU_MAX);
    if (local_mtu_ret) {
        ESP_LOGE(TAG, "set local  MTU failed, error code = %x", local_mtu_ret);
    }

    ESP_ERROR_CHECK(esp_ble_gap_start_advertising(&adv_params));
}

// ble发送数据包
void ble_sendPacket(BLE_char_list_t char_index, uint8_t *data, uint16_t len, bool is_indicate) {
    if (ble_conn_table[0].in_use) {
        uint16_t notify_conn_id = ble_conn_table[0].conn_id;
        esp_ble_gatts_send_indicate(gatt_service_info.gatts_if, notify_conn_id, gatt_service_info.uuid_nodes[char_index].char_handle, len,
                                    data, is_indicate);
    }
}

// server发送文件 notify
void ble_sendFile_notify(char *data, int data_len) {
    if (ble_conn_table[0].in_use) {
        uint16_t notify_conn_id = ble_conn_table[0].conn_id;
        esp_ble_gatts_send_indicate(gatt_service_info.gatts_if, notify_conn_id, gatt_service_info.uuid_nodes[TFN_INDEX].char_handle,
                                    data_len, (uint8_t *)data, false);
    }
}

// server 接受命令处理
static void cmd_write_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
    char *response;
    if (param->write.len > IOS_MTU_MAX) {
        ESP_LOGE(TAG, "Write data too long: %d", param->write.len);
        return;
    }
    if (param->write.value[param->write.len - 1] != '\0') {
        char tempBuf[IOS_MTU_MAX + 1];
        memcpy(tempBuf, param->write.value, param->write.len);
        tempBuf[param->write.len] = '\0'; // 确保字符串以'\0'结尾
        response = cmd_handler((char *)tempBuf, param->write.len + 1);
    } else {
        response = cmd_handler((char *)param->write.value, param->write.len);
    }
    if (response == NULL)
        return;
    ESP_LOGI(TAG, "Response: %s", response);
    esp_ble_gatts_send_indicate(gatt_service_info.gatts_if, param->write.conn_id, gatt_service_info.uuid_nodes[CMD_INDEX].char_handle,
                                strlen(response), (uint8_t *)response, true);
}

// server 接收文件处理
void recev_file_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
    if (param->write.len > IOS_MTU_MAX) {
        ESP_LOGE(TAG, "Write data too long: %d", param->write.len);
        return;
    }
    ESP_LOGI(TAG, "recv_file_handler: %d", param->write.len);
    recv_file_handler(param->write.value, param->write.len);
}
